<?php
// 这是系统自动生成的公共文件

/**
 * 随机字符
 * @param int $length 长度
 * @param string $type 类型
 * @param int $convert 转换大小写 1大写 0小写
 * @return string
 */
function gen_random($length = 10, $type = 'letter', $convert = 1): string
{
    $config = array(
        'number' => '1234567890',
        'letter' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
        'string' => 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789',
        'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
    );

    if (!isset($config[$type])) $type = 'letter';
    $string = $config[$type];

    $code = '';
    $strlen = strlen($string) - 1;
    for ($i = 0; $i < $length; $i++) {
        $code .= $string[mt_rand(0, $strlen)];
    }
    if (!empty($convert)) {
        $code = ($convert > 0) ? strtoupper($code) : strtolower($code);
    }
    return $code;
}


/**
 * 生成订单号
 * 格式：前缀字符串{Y}{M}{D}{H}{I}{S}{R8}{U6}{N2}{P2}
 * 说明：前缀字符串{Y(year)}{M(month)}{D(day)}{H(hour)}{I(minute)}{S(second)}{R(random)8}{U(Us)6}{N(node)2}{P(process)2}
 * 前缀字符串任意长度
 * {R8}生成部分的代码+默认长度
 * 每个部分都可以加任意间隔符号
 * 例如：gen_order_sn("RAISE-{Y}{M}{D}{H}{I}{S}{R8}{U6}{N2}{P2}")
 * @param string $format
 * @return string
 */
function gen_order_sn($format = 'RAISE-{Y}{M}{D}{H}{I}{S}{R2}{U2}{N2}{P2}'): string
{
    return preg_replace_callback('/\{([A-Za-z]+)(\d*)\}/', function ($matches) {
            $type = strtoupper($matches[1]);
            $digit = $matches[2];
            $length = $digit !== '' ? intval($digit) : null;

            switch ($type) {
                // 时间元素
                case 'Y':
                    return date('Y');
                case 'M':
                    return date('m');
                case 'D':
                    return date('d');
                case 'H':
                    return date('H');
                case 'I':
                    return date('i');
                case 'S':
                    return date('s');

                // 密码学安全随机数
                case 'R':
                    $len = $length ?? 8;
                    return bin2hex(random_bytes(ceil($len / 2)));

                // 微秒时间戳
                case 'U':
                    $micro = explode(' ', microtime(false));
                    $microStr = str_replace('.', '', $micro[0]);
                    $len = $length ?? 6;
                    return substr($microStr . $micro[1], 0, $len);

                // 服务器节点标识（示例值）
                case 'N':
                    return substr('A1', 0, $length ?? 2); // 需配置实际节点标识

                // 进程ID
                case 'P':
                    return str_pad(getmypid() % 100, 2, '0', STR_PAD_LEFT);

                default:
                    return $matches; // 返回原始未识别的格式
            }
        }, $format) . substr(uniqid('', true), -4); // 添加唯一后缀
}


/**
 * 递归删除目录及其所有内容
 * @param string $dir 要删除的目录的绝对路径
 * @param bool $deleteRoot 是否删除根目录本身，默认为 false (即只清空内容)
 * @return bool
 */
function delete_dir_recursively(string $dir, bool $deleteRoot = false): bool
{
    // 确保路径存在且是一个目录
    if (!is_dir($dir)) {
        return false;
    }

    // 打开目录句柄
    $handle = opendir($dir);
    if (!$handle) {
        return false;
    }

    // 遍历目录
    while (($item = readdir($handle)) !== false) {
        if ($item === '.' || $item === '..') {
            continue;
        }

        $path = $dir . DIRECTORY_SEPARATOR . $item;

        if (is_dir($path)) {
            // 如果是子目录，递归调用
            delete_dir_recursively($path, true);
        } else {
            // 如果是文件，直接删除
            unlink($path);
        }
    }

    // 关闭目录句柄
    closedir($handle);

    // 如果需要，删除根目录本身
    if ($deleteRoot) {
        return rmdir($dir);
    }

    return true;
}



/**
 * 解析前端传递的排序规则
 * 格式示例:
 * `field1|asc,field2|desc`
 * @param string|null $orderBy 排序规则字符串
 * @return array 解析后的排序规则数组，例如 `["field1" => "asc", "field2" => "desc"]`
 */
function sort_rules(?string $orderBy): array
{
    $sortRules = [];

    // 1. 检查 $orderBy 是否为空或空字符串，如果是则直接返回空数组
    if (empty($orderBy)) {
        return $sortRules;
    }

    // 2. 分割排序规则字符串
    $orderByArr = explode(',', $orderBy);

    foreach ($orderByArr as $item) {
        // 3. 清理并分割每个排序项
        $item = trim($item);
        if (empty($item)) {
            continue; // 跳过空项
        }

        $itemArr = explode('|', $item);

        // 4. 确保分割后只有两个元素 (字段和排序方向)
        if (count($itemArr) === 2) {
            $field = trim($itemArr[0]);
            $sort = strtolower(trim($itemArr[1]));

            // 5. 验证排序方向是否合法
            if (in_array($sort, ['asc', 'desc'])) {
                $sortRules[$field] = $sort;
            }
        }
    }

    return $sortRules;
}



/**
 * 递归处理项目数组，将其中'value'字段的数字字符串转换为数字类型。
 *
 * @param array $items 待处理的项目数组。
 * @return array 处理后的数组。
 */
function process_items_recursively(array &$items): array
{
    // 使用 array_walk 遍历数组中的每一个元素（每个元素都是一个关联数组，即一个item）
    // 这里使用引用传递（&$item），可以直接修改原数组的元素
    array_walk($items, function (&$item) {
        // 检查当前项目是否存在 'value' 键
        if (isset($item['value'])) {
            // is_numeric() 可以判断一个变量是否是数字或数字字符串
            // 例如：is_numeric("123") -> true, is_numeric("12.3") -> true, is_numeric("abc") -> false
            if (is_numeric($item['value'])) {
                // 进行类型转换。
                // 使用 + 0 是一种简洁的技巧，可以自动将字符串转换为整数或浮点数。
                // 例如："123" + 0 -> (int)123, "123.45" + 0 -> (float)123.45
                $item['value'] = $item['value'] + 0;
            }
        }

        // 检查是否存在 'children' 键，并且它是一个非空数组
        if (!empty($item['children']) && is_array($item['children'])) {
            // 如果存在子项目，则递归调用自身，处理子项目数组
            // 注意，这里将子数组的引用传递给递归函数
            process_items_recursively($item['children']);
        }
    });

    return $items;
}


